package de.tu_darmstadt.gdi1.xcom.tests.testcases.tutors;

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;

import de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1;

/**
 * 
 * Tests at the end of one's turn all data is correctly reset
 * 
 * @author Lukas Schwoebel
 *
 */
public class EndTurnTests {
	
	private XcomTestAdapterLevel1 testAdapter;
	
	/**
	 * @throws java.lang.Exception
	 */
	@Before
	public void setUp() throws Exception {
		testAdapter = new XcomTestAdapterLevel1();
	}

	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#endTurn()}.
	 */
	@Test
	public final void testGameStateIsKept() {
		testAdapter.loadLevelFromString(TestLevel.testLevel);

		// bring actionpoints down to zero for first player by rotation
		for(int i = 0; i < TestLevel.actionPoints; i++) {
			testAdapter.rotateActivePlayer( ((i % 2) == 0) );
		}
		assertEquals("Actionpoints of player should be zero after "+TestLevel.actionPoints+" rotations", 0, testAdapter.actionPointsLeft());
		
		// make some "random" actions with other player
		testAdapter.changeActivePlayer(1, 4);
		testAdapter.rotateActivePlayer(true);		// 74
		testAdapter.performActionForActivePlayer();	// 71
		testAdapter.rotateActivePlayer(false);		// 70
		testAdapter.performActionForActivePlayer();	// 67 
		testAdapter.performActionForActivePlayer(); // 57 kill alien
		testAdapter.performActionForActivePlayer(); // 54
		testAdapter.rotateActivePlayer(false);		// 53
		testAdapter.performActionForActivePlayer();	// 43 kill alien
		testAdapter.rotateActivePlayer(true);		// 42
		testAdapter.performActionForActivePlayer();	// 39
		testAdapter.rotateActivePlayer(true);		// 38
		testAdapter.performActionForActivePlayer();	// 35
		testAdapter.rotateActivePlayer(true);		// 34 now looking south at 3:1
		assertEquals("Actionpoints of player should be 34 after some actions", 34, testAdapter.actionPointsLeft());
		
		// now end turn
		testAdapter.endTurn();
		
		assertEquals("Actionpoints of player should be reset after end turn", 75, testAdapter.actionPointsLeft());
		// to be sure, change to this player explicitly
		testAdapter.changeActivePlayer(3, 1);
		assertEquals("Actionpoints of player should be reset after end turn", 75, testAdapter.actionPointsLeft());
		
		// test if gamestate is kept, selected player (should be at 2:1) and looking south
		assertEquals("After end turn the selected player (3:1) should still be looking south:\n"+testAdapter.levelRepresentationAsString(),
				3, testAdapter.activePlayerLookingToDirection());
		// first player at 9:2 should face east
		testAdapter.changeActivePlayer(9, 2);
		// test if gamestate is kept, selected player (should be at 9:2) and looking easat
		assertEquals("After end turn the selected player (9:2) should still be looking east:\n"+testAdapter.levelRepresentationAsString(),
				2, testAdapter.activePlayerLookingToDirection());
		
		// there is no zombie on 1:2
		assertEquals("A killed zombie at 1:2 should still be dead after end turn:\n"+testAdapter.levelRepresentationAsString(),
				'.', testAdapter.elementOnPosition(1, 2));
		// there is no zombie on 2:2
		assertEquals("A killed zombie at 2:2 should still be dead after end turn:\n"+testAdapter.levelRepresentationAsString(),
				'.', testAdapter.elementOnPosition(2, 2));
		// player at 1:4 moved
		assertEquals("The player at 1:4 moved to 2:1:\n"+testAdapter.levelRepresentationAsString(),
				'.', testAdapter.elementOnPosition(1, 4));
		// player at 1:4 moved
		assertEquals("The player at 1:4 moved to 3:1:\n"+testAdapter.levelRepresentationAsString(),
				'@', testAdapter.elementOnPosition(3, 1));
				
	}
	

	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#endTurn()}.
	 */
	@Test
	public final void testWonAfterEndTurn() {
		
		String testLevelStringLost = "" +
				"######\n" +
				"#...##\n" +
				"##..##\n" +
				"######\n" +
				"//{mobs}\n" +
				"//Z;2;1;n;50;75;50;50;0";
		String testLevelStringWon = "" +
				"######\n" +
				"#...##\n" +
				"##..##\n" +
				"######\n" +
				"//{mobs}\n" +
				"//@;1;1;n;50;75;50;50;0";
		
		testAdapter.loadLevelFromString(testLevelStringLost);
		assertTrue("Level should be lost as there is no player left:\n"+testAdapter.levelRepresentationAsString(), testAdapter.isLost());
		assertFalse("Level cant be won as there is no player left but a zombie:\n"+testAdapter.levelRepresentationAsString(), testAdapter.isWon());

		// first test - there should be no exception calling endTurn at a lost game
		try {
			testAdapter.endTurn();
		}
		catch(Exception e) {
			fail("After a game is lost, there should be no exception if endTurn is called!");
			e.printStackTrace();
		}
		// now the gamestate should be the same
		assertEquals("After end turn level is still lost:\n"+testAdapter.levelRepresentationAsString(), true, testAdapter.isLost());
		assertEquals("After end turn level is still not won:\n"+testAdapter.levelRepresentationAsString(), false, testAdapter.isWon());
		
		
		// same test for a won level
		testAdapter.loadLevelFromString(testLevelStringWon);
		assertEquals("Level should is not lost as there is a player and no zombie:\n"+testAdapter.levelRepresentationAsString(), false, testAdapter.isLost());
		assertEquals("Level is won, there is a player but no zombie:\n"+testAdapter.levelRepresentationAsString(), true, testAdapter.isWon());

		// first test - there should be no exception calling endTurn at a lost game
		try {
			testAdapter.endTurn();
		}
		catch(Exception e) {
			fail("After a game is won, there should be no exception if endTurn is called");
		}
		// now the gamestate should be the same
		assertEquals("After end turn level is still not lost:\n"+testAdapter.levelRepresentationAsString(), false, testAdapter.isLost());
		assertEquals("After end turn level is still won:\n"+testAdapter.levelRepresentationAsString(), true, testAdapter.isWon());		
	}
	

	/**
	 * Test method for {@link de.tu_darmstadt.gdi1.xcom.tests.adapters.XcomTestAdapterLevel1#endTurn()}.
	 */
	@Test
	public final void testNoActionAfterWonOrLost() {
		// NOTE: this test could be at LevelWonTest, too, but as there is endTurn concerned, we test it in here

		String testLevelStringWon = "" +
				"######\n" +
				"#...##\n" +
				"##..##\n" +
				"######\n" +
				"//{mobs}\n" +
				"//@;1;1;e;50;75;50;50;0";
		
		testAdapter.loadLevelFromString(testLevelStringWon);
		
		// now select the player and try to turn
		testAdapter.changeActivePlayer(1, 1);
		testAdapter.rotateActivePlayer(true);
		assertEquals("After the game is won, no actions are possible any more, player should still look east", 2, testAdapter.activePlayerLookingToDirection());
		// try to walk
		testAdapter.performActionForActivePlayer();
		assertEquals("After the game is won, no actions are possible, player should still be at 1:1\n"+testAdapter.levelRepresentationAsString(),
				'@', testAdapter.elementOnPosition(1, 1));
		assertEquals("After the game is won, no actions are possible, player should still be at 1:1\n"+testAdapter.levelRepresentationAsString(),
				'.', testAdapter.elementOnPosition(2, 1));
		
		// now we test the same, but the game should be lost, so add a zombie and end turn 3 times
		testLevelStringWon += "\n//Z;2;2;e;50;75;50;50;0";
		
		testAdapter.loadLevelFromString(testLevelStringWon);
		testAdapter.endTurn();
		testAdapter.endTurn();
		testAdapter.endTurn();
		assertEquals("After three turns the level should be lost, there is still a zombie in the level\n"+testAdapter.levelRepresentationAsString(),
				true, testAdapter.isLost());
		// now try to turn
		testAdapter.rotateActivePlayer(true);
		assertEquals("After the game is lost, no actions are possible any more, player should still look east", 2, testAdapter.activePlayerLookingToDirection());
		// try to walk
		testAdapter.performActionForActivePlayer();
		assertEquals("After the game is lost, no actions are possible, player should still be at 1:1\n"+testAdapter.levelRepresentationAsString(),
				'@', testAdapter.elementOnPosition(1, 1));
		assertEquals("After the game is lost, no actions are possible, player should still be at 1:1\n"+testAdapter.levelRepresentationAsString(),
				'.', testAdapter.elementOnPosition(2, 1));		
		
	}
}
